<?php
/**
 * Copyright (c) 2020
 * 摘    要：
 * 作    者：san
 * 修改日期：2020.04.03
 */

namespace App\Model;

use App\Library\Traits\Helper;
use DateTime;
use ErrorException;
use Hyperf\Database\Model\SoftDeletes;
use Hyperf\Utils\Context;

/**
 * This is the model class for table "project".
 *
 * @property integer $id
 * @property integer $user_id
 * @property string $name
 * @property integer $level
 * @property integer $workspace_id
 * @property integer $status
 * @property string $version
 * @property string $gray_version
 * @property string $repo_url
 * @property string $repo_username
 * @property string $repo_password
 * @property string $repo_mode
 * @property string $repo_type
 * @property string $deploy_from
 * @property string $excludes
 * @property string $release_user
 * @property string $release_to
 * @property string $release_library
 * @property string $hosts
 * @property string $aliyun_sync
 * @property string $aliyun_id
 * @property string $aliyun_region
 * @property string $aliyun_listen_port
 * @property string $is_open_gray
 * @property string $gray_hosts
 * @property string $pre_deploy
 * @property string $post_deploy
 * @property string $pre_release
 * @property string $post_release
 * @property string $post_release_delay
 * @property integer $audit
 * @property integer $ansible
 * @property integer $keep_version_num
 * @property DateTime $created_at
 * @property DateTime $updated_at
 */
class Project extends Model
{
    use SoftDeletes;
    use Helper;

    protected $table = 'project';

    protected $hidden = ['repo_username', 'repo_password', 'created_at', 'updated_at', 'deleted_at'];

    protected $fillable = ['name'];

    const IS_OPEN_GRAY       = 1;
    const NONE_OPEN_GRAY     = 0;
    const AUDIT_YES          = 1;
    const REPO_MODE_BRANCH   = 'branch';
    const REPO_MODE_TAG      = 'tag';
    const REPO_MODE_NONTRUNK = 'nontrunk';
    const REPO_GIT           = 'git';
    const REPO_SVN           = 'svn';

    /**
     * @param $id
     * @return bool
     */
    public static function getInstance($id)
    {
        if (!Context::get('PROJECT_CONF')) {
            Context::set('PROJECT_CONF', static::query()->find($id));
        }

        return Context::get('PROJECT_CONF');
    }

    /**
     * 获取Ansible Host File
     *
     * @param int $projectId
     * @throws ErrorException
     * @return string
     */
    public static function getAnsibleHostsFile($projectId = 0)
    {
        if (!$projectId) {
            $projectId = Context::get('PROJECT_CONF')->id;
        }

        if (!$projectId) {
            throw new ErrorException(t("message.12023"));
        }

        return sprintf('%s/project_%d', rtrim(config('autods')['ansible_hosts_dir'], '/'), $projectId);
    }

    /**
     * 获取Ansible Host File
     *
     * @param int $projectId
     * @throws ErrorException
     * @return string
     */
    public static function getAnsibleGrayHostsFile($projectId = 0)
    {
        if (!$projectId) {
            $projectId = Context::get('PROJECT_CONF')->id;
        }

        if (!$projectId) {
            throw new ErrorException(t("message.12023"));
        }

        return sprintf('%s/project_%d_gray', rtrim(config('autods')['ansible_hosts_dir'], '/'), $projectId);
    }

    /**
     * 拼接宿主机的仓库目录
     * {deploy_from}/{env}/{project}
     *
     * @return string
     */
    public static function getDeployFromDir()
    {
        $from    = Context::get('PROJECT_CONF')->deploy_from;
        $env     = Environment::getAliasMap(Context::get('PROJECT_CONF')->level) ?? 'unknow';
        $project = static::getGitProjectName(Context::get('PROJECT_CONF')->repo_url);

        return sprintf("%s/%s/%s", rtrim($from, '/'), rtrim($env, '/'), $project);
    }

    /**
     * 根据git地址获取项目名字
     *
     * @param $gitUrl
     * @return mixed
     */
    public static function getGitProjectName($gitUrl)
    {
        if (preg_match('#.*/(.*?)\.git#', $gitUrl, $match)) {
            return $match[1];
        }

        return basename($gitUrl);;
    }

    /**
     * 拼接宿主机的部署隔离工作空间
     * {deploy_from}/{env}/{project}-Ymd-His
     *
     * @param $version
     * @return string
     */
    public static function getDeployWorkspace($version)
    {
        $from    = Context::get('PROJECT_CONF')->deploy_from;
        $env     = Environment::getAliasMap(Context::get('PROJECT_CONF')->level) ?? 'unknow';
        $project = static::getGitProjectName(Context::get('PROJECT_CONF')->repo_url);

        return sprintf("%s/%s/%s-%s", rtrim($from, '/'), rtrim($env, '/'), $project, $version);
    }

    /**
     * 获取 ansible 宿主机tar文件路径
     *
     * {deploy_from}/{env}/{project}-YYmmdd-HHiiss.tar.gz
     *
     * @param $version
     * @return string
     */
    public static function getDeployPackagePath($version)
    {
        return sprintf('%s.tar.gz', static::getDeployWorkspace($version));
    }

    /**
     * 拼接宿主机的SVN仓库目录(带branches/tags目录)
     *
     * @param string $branchName
     * @return string
     */
    public static function getSvnDeployBranchFromDir($branchName = 'trunk')
    {
        $deployFromDir = static::getDeployFromDir();
        $branchFromDir = '';

        if ($branchName == '') {
            $branchFromDir = $deployFromDir;
        } elseif ($branchName == 'trunk') {
            $branchFromDir = sprintf('%s/trunk', $deployFromDir);
        } elseif (Context::get('PROJECT_CONF')->repo_mode == static::REPO_MODE_BRANCH) {
            $branchFromDir = sprintf('%s/branches/%s', $deployFromDir, $branchName);
        } elseif (Context::get('PROJECT_CONF')->repo_mode == static::REPO_MODE_TAG) {
            $branchFromDir = sprintf('%s/tags/%s', $deployFromDir, $branchName);
        }

        return $branchFromDir;
    }

    /**
     * 获取目标机要发布的目录
     * {webroot}
     *
     * @return string
     */
    public static function getTargetWorkspace()
    {
        return rtrim(Context::get('PROJECT_CONF')->release_to, '/');
    }

    /**
     * 拼接目标机要发布的目录
     * {release_library}/{project}/{version}
     *
     * @param $version
     * @return string
     */
    public static function getReleaseVersionDir($version = '')
    {
        return sprintf('%s/%s/%s', rtrim(Context::get('PROJECT_CONF')->release_library, '/'),
            static::getGitProjectName(Context::get('PROJECT_CONF')->repo_url), $version);
    }

    /**
     * 拼接目标机要发布的打包文件路径
     * {release_library}/{project}/{version}.tar.gz
     *
     * @param string $version
     * @return string
     */
    public static function getReleaseVersionPackage($version = '')
    {
        return sprintf('%s.tar.gz', static::getReleaseVersionDir($version));
    }

    /**
     * 获取当前进程配置的目标机器host列表
     */
    public static function getHosts()
    {
        return str2arr(Context::get('PROJECT_CONF')->hosts);
    }

    /**
     * 获取当前进程配置的灰度目标机器host列表
     */
    public static function getGrayHosts()
    {
        return str2arr(Context::get('PROJECT_CONF')->gray_hosts);
    }

    /**
     * 获取当前进程配置的ansible状态
     *
     * @return boolean
     */
    public static function getAnsibleStatus()
    {
        return (bool)Context::get('PROJECT_CONF')->ansible;
    }
}
